// Copyright (c) Microsoft Corporation.  All rights reserved.
// DPWSSideShowDeviceSimulatorDlg.cpp : implementation file
//

#include "stdafx.h"
#include <strsafe.h>
#include "DPWSSideShowDeviceSimulator.h"
#include "DPWSSideShowDeviceSimulatorDlg.h"

#include "DPWSServiceWrapper.h"

#include "EventSourceNotificationUtility.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

const unsigned int DefaultWidth = 320;
const unsigned int DefaultHeight = 240;
const unsigned int DefaultDepth = 24;

// CAboutDlg dialog used for App About

class CAboutDlg : public CDialog
{
public:
    CAboutDlg();

// Dialog Data
    enum { IDD = IDD_ABOUTBOX };

    protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support

// Implementation
protected:
    DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialog::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
END_MESSAGE_MAP()


// CDPWSSideShowDeviceSimulatorDlg dialog


//------------------------------------------------------------------------------
// CDPWSSideShowDeviceSimulatorDlg::CDPWSSideShowDeviceSimulatorDlg
//      Constructor
//------------------------------------------------------------------------------
CDPWSSideShowDeviceSimulatorDlg::CDPWSSideShowDeviceSimulatorDlg(CWnd* pParent /*=NULL*/)
    : CDialog(CDPWSSideShowDeviceSimulatorDlg::IDD, pParent),
    m_SideShowDisplayFormat(DefaultWidth, DefaultHeight, DefaultDepth)
{
    m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
    m_pDPWSService = NULL;
    m_pBuffer = NULL;
    m_ClientID = _T("");
    m_BufferSize = 0;
    m_TextHeight = 0;
}

void CDPWSSideShowDeviceSimulatorDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialog::DoDataExchange(pDX);
    DDX_Control(pDX, IDC_BACK, m_buttonBack);
    DDX_Control(pDX, IDC_MENU, m_buttonMenu);
    DDX_Control(pDX, IDC_ENTER, m_buttonEnter);
    DDX_Control(pDX, IDC_LEFT, m_buttonLeft);
    DDX_Control(pDX, IDC_UP, m_buttonUp);
    DDX_Control(pDX, IDC_DOWN, m_buttonDown);
    DDX_Control(pDX, IDC_RIGHT, m_buttonRight);
}

BEGIN_MESSAGE_MAP(CDPWSSideShowDeviceSimulatorDlg, CDialog)
    ON_WM_SYSCOMMAND()
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    //}}AFX_MSG_MAP
    ON_WM_SIZE()
    ON_WM_DESTROY()
    ON_MESSAGE(WM_SIDESHOW_UPDATE,OnSideshowUpdate)
    ON_BN_CLICKED(IDC_BACK, CDPWSSideShowDeviceSimulatorDlg::OnBnClickedBack)
    ON_BN_CLICKED(IDC_MENU, CDPWSSideShowDeviceSimulatorDlg::OnBnClickedMenu)
    ON_BN_CLICKED(IDC_ENTER, CDPWSSideShowDeviceSimulatorDlg::OnBnClickedEnter)
    ON_BN_CLICKED(IDC_LEFT, CDPWSSideShowDeviceSimulatorDlg::OnBnClickedLeft)
    ON_BN_CLICKED(IDC_UP, CDPWSSideShowDeviceSimulatorDlg::OnBnClickedUp)
    ON_BN_CLICKED(IDC_DOWN, CDPWSSideShowDeviceSimulatorDlg::OnBnClickedDown)
    ON_BN_CLICKED(IDC_RIGHT, CDPWSSideShowDeviceSimulatorDlg::OnBnClickedRight)
END_MESSAGE_MAP()


// CDPWSSideShowDeviceSimulatorDlg message handlers

BOOL CDPWSSideShowDeviceSimulatorDlg::OnInitDialog()
{
    CDialog::OnInitDialog();

    // Add "About..." menu item to system menu.

    // IDM_ABOUTBOX must be in the system command range.
    ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
    ASSERT(IDM_ABOUTBOX < 0xF000);

    CMenu* pSysMenu = GetSystemMenu(FALSE);
    if (pSysMenu != NULL)
    {
        CString strAboutMenu;
        strAboutMenu.LoadString(IDS_ABOUTBOX);
        if (!strAboutMenu.IsEmpty())
        {
            pSysMenu->AppendMenu(MF_SEPARATOR);
            pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
        }
    }

    // Set the icon for this dialog.  The framework does this automatically
    //  when the application's main window is not a dialog
    SetIcon(m_hIcon, TRUE);         // Set big icon
    SetIcon(m_hIcon, FALSE);        // Set small icon

    HRESULT hr = InitializeSideShow();

    if (S_OK != hr)
    {
        const size_t MaxMessageSize = 256;

        WCHAR buf[MaxMessageSize];
        StringCchPrintf(buf, MaxMessageSize, 
            L"Fatal Error: initialize SideShow Service failed, error code %x\r\n", 
            hr);

        ::MessageBox(NULL, buf, L"DPWS SideShow Bitmap Driver Simulator", MB_ICONERROR | MB_OK);
        EndDialog(hr);
        return FALSE;
    }

    return TRUE;  // return TRUE  unless you set the focus to a control
}

HRESULT CDPWSSideShowDeviceSimulatorDlg::InitializeSideShow()
{
    if (!AllocSideShowFrameBuffer())
        return E_OUTOFMEMORY;

    HRESULT hr = StartDPWSService();
    if (S_OK != hr)
        FreeSideShowFrameBuffer();
    return hr;
}

HRESULT CDPWSSideShowDeviceSimulatorDlg::StartDPWSService()
{
     // Create and initialize Windows SideShow-compatible device and service
     if (m_pDPWSService)
          return S_OK;

    m_pDPWSService = new CDPWSServiceWrapper;
    if (!m_pDPWSService)
        return E_OUTOFMEMORY;

    HRESULT hr = m_pDPWSService->Initialize(this);

    if (S_OK != hr)
    {
        delete m_pDPWSService;
        m_pDPWSService = NULL;
    }

    return hr;
}

void CDPWSSideShowDeviceSimulatorDlg::StopDPWSService()
{
    // Stop and release device
    if (m_pDPWSService)
    {
        m_pDPWSService->StopService();
        delete m_pDPWSService;
        m_pDPWSService = NULL;
    }
}

bool CDPWSSideShowDeviceSimulatorDlg::AllocSideShowFrameBuffer()
{
    // initialize SideShow buffer
    ULONG width = m_SideShowDisplayFormat.m_width;
    ULONG height = m_SideShowDisplayFormat.m_height;
    ULONG depth = m_SideShowDisplayFormat.m_depth;

    ULONG overhead = sizeof(BITMAPFILEHEADER) 
        + sizeof(BITMAPINFOHEADER);

    // palette
    ULONG paletteSize = 0;
    if (depth < 24)
    {
        paletteSize = (ULONG)(1 << depth) * sizeof(RGBQUAD);
    }

    m_BufferSize = (width * depth + 31) / 32 * 4 * height + overhead + paletteSize;

    m_pBuffer = new BYTE[m_BufferSize];
    return m_pBuffer != NULL;
}

void CDPWSSideShowDeviceSimulatorDlg::FreeSideShowFrameBuffer() 
{
    if (m_pBuffer)
    {
        delete [] m_pBuffer;
        m_pBuffer = NULL;
    }
}

void CDPWSSideShowDeviceSimulatorDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
    if ((nID & 0xFFF0) == IDM_ABOUTBOX)
    {
        CAboutDlg dlgAbout;
        dlgAbout.DoModal();
    }
    else
    {
        CDialog::OnSysCommand(nID, lParam);
    }
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CDPWSSideShowDeviceSimulatorDlg::OnPaint()
{
    if (IsIconic())
    {
        CPaintDC dc(this); // device context for painting

        SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

        // Center icon in client rectangle
        int cxIcon = GetSystemMetrics(SM_CXICON);
        int cyIcon = GetSystemMetrics(SM_CYICON);
        CRect rect;
        GetClientRect(&rect);
        int x = (rect.Width() - cxIcon + 1) / 2;
        int y = (rect.Height() - cyIcon + 1) / 2;

        // Draw the icon
        dc.DrawIcon(x, y, m_hIcon);
    }
    else
    {
        PaintBitmap(m_pBuffer);
        CDialog::OnPaint();
    }
}

// The system calls this function to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CDPWSSideShowDeviceSimulatorDlg::OnQueryDragIcon()
{
    return static_cast<HCURSOR>(m_hIcon);
}

//------------------------------------------------------------------------------
// CDPWSSideShowDeviceSimulatorDlg::OnSize
//      When main window is resized, adjust the postion of all controls
//------------------------------------------------------------------------------
void CDPWSSideShowDeviceSimulatorDlg::OnSize(UINT nType, int cx, int cy)
{
    CDialog::OnSize(nType, cx, cy);

    if (GetDlgItem(IDC_BACK) != NULL)
    {
        GetDlgItem(IDC_BACK)->SetWindowPos(NULL, 0, cy - 100, 0, 0, SWP_NOSIZE);
    }
    if (GetDlgItem(IDC_MENU) != NULL)
    {
        GetDlgItem(IDC_MENU)->SetWindowPos(NULL, 100, cy - 100, 0, 0, SWP_NOSIZE);
    }
    if (GetDlgItem(IDC_ENTER) != NULL)
    {
        GetDlgItem(IDC_ENTER)->SetWindowPos(NULL, 200, cy - 100, 0, 0, SWP_NOSIZE);
    }
    if (GetDlgItem(IDC_LEFT) != NULL)
    {
        GetDlgItem(IDC_LEFT)->SetWindowPos(NULL, 300, cy - 100, 0, 0, SWP_NOSIZE);
    }
    if (GetDlgItem(IDC_UP) != NULL)
    {
        GetDlgItem(IDC_UP)->SetWindowPos(NULL, 350, cy - 120, 0, 0, SWP_NOSIZE);
    }
    if (GetDlgItem(IDC_DOWN) != NULL)
    {
        GetDlgItem(IDC_DOWN)->SetWindowPos(NULL, 350, cy - 80, 0, 0, SWP_NOSIZE);
    }
    if (GetDlgItem(IDC_RIGHT) != NULL)
    {
        GetDlgItem(IDC_RIGHT)->SetWindowPos(NULL, 450, cy - 100, 0, 0, SWP_NOSIZE);
    }
}

//------------------------------------------------------------------------------
// CDPWSSideShowDeviceSimulatorDlg::OnDestroy
//      When destroy main window, stop and release DPWS device, and destroy 
// SideShow display window
//------------------------------------------------------------------------------
void CDPWSSideShowDeviceSimulatorDlg::OnDestroy()
{
    CDialog::OnDestroy();

    // Stop and release device
    StopDPWSService();

    FreeSideShowFrameBuffer();
}

//------------------------------------------------------------------------------
// CDPWSSideShowDeviceSimulatorDlg::OnBnClickedBack
//      Respond user's clicking on "back" button
//------------------------------------------------------------------------------
void CDPWSSideShowDeviceSimulatorDlg::OnBnClickedBack()
{

    CEventSourceNotificationUtility::GetInstance()->SideShowButtonPressedEvent(
        L"Back", GetClientID()
    );
}

//------------------------------------------------------------------------------
// CDPWSSideShowDeviceSimulatorDlg::OnBnClickedMenu
//      Respond user's clicking on "menu" button
//------------------------------------------------------------------------------
void CDPWSSideShowDeviceSimulatorDlg::OnBnClickedMenu()
{

    CEventSourceNotificationUtility::GetInstance()->SideShowButtonPressedEvent(
        L"Menu", GetClientID()
    );
}

//------------------------------------------------------------------------------
// CDPWSSideShowDeviceSimulatorDlg::OnBnClickedEnter
//      Respond user's clicking on "OK" button
//------------------------------------------------------------------------------
void CDPWSSideShowDeviceSimulatorDlg::OnBnClickedEnter()
{

    CEventSourceNotificationUtility::GetInstance()->SideShowButtonPressedEvent(
        L"Select", GetClientID()
    );
}

//------------------------------------------------------------------------------
// CDPWSSideShowDeviceSimulatorDlg::OnBnClickedLeft
//      Respond user's clicking on "left" button
//------------------------------------------------------------------------------
void CDPWSSideShowDeviceSimulatorDlg::OnBnClickedLeft()
{

    CEventSourceNotificationUtility::GetInstance()->SideShowButtonPressedEvent(
        L"Previous", GetClientID()
    );
}

//------------------------------------------------------------------------------
// CDPWSSideShowDeviceSimulatorDlg::OnBnClickedUp
//      Respond user's clicking on "up" button
//------------------------------------------------------------------------------
void CDPWSSideShowDeviceSimulatorDlg::OnBnClickedUp()
{

    CEventSourceNotificationUtility::GetInstance()->SideShowButtonPressedEvent(
        L"Up", GetClientID()
    );
}

//------------------------------------------------------------------------------
// CDPWSSideShowDeviceSimulatorDlg::OnBnClickedDown
//      Respond user's clicking on "down" button
//------------------------------------------------------------------------------
void CDPWSSideShowDeviceSimulatorDlg::OnBnClickedDown()
{

    CEventSourceNotificationUtility::GetInstance()->SideShowButtonPressedEvent(
        L"Down", GetClientID()
    );
}

//------------------------------------------------------------------------------
// CDPWSSideShowDeviceSimulatorDlg::OnBnClickedRight
//      Respond user's clicking on "right" button
//------------------------------------------------------------------------------
void CDPWSSideShowDeviceSimulatorDlg::OnBnClickedRight()
{

    CEventSourceNotificationUtility::GetInstance()->SideShowButtonPressedEvent(
        L"Next", GetClientID()
    );
}

//------------------------------------------------------------------------------
// CDPWSSideShowDeviceSimulatorDlg::OnSideshowUpdate
//      Respond SideShow picture updated message
//------------------------------------------------------------------------------
LRESULT CDPWSSideShowDeviceSimulatorDlg::OnSideshowUpdate(WPARAM wParam,
                                       LPARAM lParam)
{
    Invalidate();
    return S_OK;
}

//------------------------------------------------------------------------------
// CDPWSSideShowDeviceSimulatorDlg::GetFrameBuffer
//      Return SideShow picture buffer and size
//------------------------------------------------------------------------------
void CDPWSSideShowDeviceSimulatorDlg::GetFrameBuffer(BYTE** pBuf, ULONG* size)
{
    *pBuf = m_pBuffer;
    *size = m_BufferSize;
}

//------------------------------------------------------------------------------
// CDPWSSideShowDeviceSimulatorDlg::GetClientID
//      Return current client ID
//------------------------------------------------------------------------------
CString CDPWSSideShowDeviceSimulatorDlg::GetClientID()
{
    return m_ClientID;
}

//------------------------------------------------------------------------------
// CDPWSSideShowDeviceSimulatorDlg::SetClientID
//      Set client ID
//------------------------------------------------------------------------------
void CDPWSSideShowDeviceSimulatorDlg::SetClientID(CString id)
{
    m_ClientID = id;
}

//------------------------------------------------------------------------------
// CDPWSSideShowDeviceSimulatorDlg::PaintBitmap
//      Redraw SideShow picture on SideShow display window
//------------------------------------------------------------------------------
void CDPWSSideShowDeviceSimulatorDlg::PaintBitmap(BYTE* pBuf)
{
    if (m_pBuffer == NULL)
    {
        return;
    }

    BITMAPFILEHEADER *pbmf;
    BITMAPINFOHEADER *pbmi;
    BYTE *bits;

    pbmf = (BITMAPFILEHEADER *)pBuf;
    pbmi = (BITMAPINFOHEADER *)(pBuf + sizeof(BITMAPFILEHEADER));
    bits = (BYTE*)pBuf + pbmf->bfOffBits;

    CPaintDC dc(this);

    ::SetDIBitsToDevice(
        dc.m_hDC,
        0,
        0,
        pbmi->biWidth,
        abs(pbmi->biHeight),
        0,
        0,
        0,
        abs(pbmi->biHeight),
        bits,
        (BITMAPINFO *)pbmi,
        DIB_RGB_COLORS);
    dc.TextOut(0, m_SideShowDisplayFormat.m_height, m_ClientID);    
}

void CDPWSSideShowDeviceSimulatorDlg::SetSideShowDisplayFormat(const CSideShowDisplayFormat& format)
{
    m_SideShowDisplayFormat = format;
}

void CDPWSSideShowDeviceSimulatorDlg::GetSideShowDisplayFormat(CSideShowDisplayFormat& format) const
{
    format = m_SideShowDisplayFormat;
}
